#include "Scanner.h"

/* */
void initScanner(char ptr filename)
{
    file = fopen (filename, "r");
	if (file equ NULL)
	{
		printf ("Can not open file: %s.\n", filename);
		exit(1);
	}

	logfile = fopen ("log.txt", "w");
	if(logfile equ NULL)
	{
	    printf ("Can not open file: log.txt\n");
		exit(1);
	}

    time_t t;
    time(&t);
	fprintf(logfile, "Init Primeval - Scanner at Time: %s\n", ctime(&t));

	errCount = 0;

	initKeyTab();
    curKey = (key_type) malloc (sizeof(struct key));
    curKey-> value = (string_t) malloc (VALLENGTH * sizeof (char));

	lnCounter = 1;
    colCounter = 1;
    curKey-> length = 0;
    nextChar();
    if(read equ EOF)
	{
	    curKey-> sym = ENDF;
	    printf("EOF!\n");
        fclose(file);
	}
}

void clearOld()
{
    int i = 0;
    while (i < curKey-> length)
    {
        curKey-> value[i] = '\0';
        i = i + 1;
    }
    curKey-> value[0] = current;
    curKey-> length = 1;
}

void get()
{
    clearOld();
    forgetSpaces();

    curKey-> column = colCounter;
    curKey-> line = lnCounter;
    int commentFound = 0;

    if (current equ ';')
    {
        curKey-> sym = COLON;
        nextChar();
    }
    elif (current equ '"')
    {
        string();
    }
    elif (current equ ')')
    {
        curKey-> sym = RPAREN;
        nextChar();
    }
    elif (current equ '}')
    {
        curKey-> sym = RBRACE;
        nextChar();
    }
    elif (current equ ']')
    {
        curKey-> sym = RBRAK;
        nextChar();
    }
    elif (current equ '*')
    {
        curKey-> sym = TIMES;
        nextChar();
    }
    elif (current equ '(')
    {
        curKey-> sym = LPAREN;
        nextChar();
    }
    elif (current equ '[')
    {
        curKey-> sym = LBRAK;
        nextChar();
    }
    elif (current equ '{')
    {
        curKey-> sym = LBRACE;
        nextChar();
    }
    elif (current equ '/')
    {
        nextChar();
        if(current equ '*')
        {
            mark("!!!Comment start!!!", 0);
            skipComment();
            commentFound = 1;
        }
        else
        {
            curKey-> sym = DIV;
        }
    }
    elif (current equ '%')
    {
        curKey-> sym = MOD;
        nextChar();
    }
    elif (current equ '+')
    {
        curKey-> sym = PLUS;
        nextChar();
    }
    elif (current equ '-')
    {
        nextChar();
        if(current equ '>')
        {
            curKey-> sym = ARROW;
            nextChar();
        }
        else
        {
            curKey-> sym = MINUS;
        }
    }
    elif (current equ '!')
    {
        curKey-> sym = NOT;
        nextChar();
    }
    elif (current equ '=')
    {
        curKey-> sym = BECOME;
        nextChar();
    }
    elif (current equ '<')
    {
        nextChar();
        if(current equ '=')
        {
            curKey-> sym = LEQ;
            nextChar();
        }
        else
        {
            curKey-> sym = LSS;
        }
    }
    elif (current equ '>')
    {
        nextChar();
        if(current equ '=')
        {
            curKey-> sym = GEQ;
            nextChar();
        }
        else
        {
            curKey-> sym = GRT;
        }
    }
    elif (current equ ',')
    {
        curKey-> sym = COMMA;
        nextChar();
    }
    elif (current equ '.')
    {
        curKey-> sym = PERIOD;
        nextChar();
    }
    elif((current >= 97 and current <= 122) or //a ... z
         (current >= 65 and current <= 90) or
         (current equ 95))  //A ... Z
    {
        nextChar();
            //Identifier
        while((current >= 97 and current <= 122) or //a ... z
              (current >= 65 and current <= 90)  or //A ... Z
              (current >= 48 and current <= 57) or
              (current equ 95))    //0 ... 9
        {
            nextChar();
        }
        curKey-> length = curKey-> length - 1;
        curKey-> sym = IDENT;
        keyword();
        curKey-> length = curKey-> length + 1;
    }
    elif(current >= 48 and current <= 57) //0 ... 9
    {
        nextChar();
        while(current >= 48 and current <= 57)
        {
            nextChar();
        }
        curKey-> sym = NUMBER;
    }
    elif(current equ '\'')
    {
        nextChar();
        if(current equ '\\')
        {
            nextChar();
            if(current neq 't' and
               current neq 'n' and
               current neq 'r' and
               current neq '\'' and
               current neq '\\' and
               current neq '0')
            {
                curKey-> sym = UNKN;
            }
            else
            {
                nextChar();
                if(current equ '\'')
                {
                    curKey-> sym = CHAR;
                    nextChar();
                }
                else
                {
                    curKey-> sym = UNKN;
                }
            }
        }
        else
        {
            nextChar();
            if(current equ '\'')
            {
                curKey-> sym = CHAR;
                nextChar();
            }
            else
            {
                curKey-> sym = UNKN;
            }
        }
    }
    elif(read neq EOF)
    {
        curKey-> sym = UNKN;
        nextChar();
    }

    if(commentFound equ 0 and curKey-> sym neq ENDF)
    {
        curKey-> length = curKey-> length - 1;
        // printSymInfo();
    }
}

void string()
{
    if (current equ '"')
    {
        nextChar();
        while(current neq '"' and curKey-> sym neq ENDF)
        {
            nextChar();
        }
        if(curKey-> sym equ ENDF)
        {
            mark("String has no end\n", 1);
            return;
        }
        else
        {
            curKey-> sym = STRING;
            nextChar();
        }
    }
}

void printSymInfo()
{
    printf("\nNext Sym\n********\n");
    string_t value = (string_t) malloc(curKey-> length * sizeof(char));
    strncpy(value, curKey-> value, curKey-> length);
    value[curKey-> length] = '\0';
    printf("Sym: %d   \"%s\"\n", curKey-> sym, value);

}
void skipComment()
{
    while(current neq '*' and curKey-> sym neq ENDF)
    {
        nextChar();
        curKey-> length = 0;
    }
    if(curKey-> sym neq ENDF)
    {
        nextChar();
    }

    if(current neq '/' and curKey-> sym neq ENDF)
    {
        skipComment();
    }
    else
    {
        nextChar();
        mark("!!!Comment   end!!!", 0);
        get();
    }
}

void forgetSpaces()
{
    while((current equ ' ' or current equ '\n' or current equ '\t' or current equ '\r') and curKey-> sym neq ENDF)
    {
        curKey-> length = curKey-> length - 1;
        nextChar();
    }
}

void keyword()
{
    int j = 0;
    while(j < KEYTABLENGTH)
    {
        if(keyTab[j]-> length equ curKey-> length)
        {
            int equality = 0;
            int i = 0;
            while(i < curKey-> length)
            {
                if(keyTab[j]-> value[i] equ curKey-> value[i])
                {
                    equality++;
                }
                i++;
            }
            if(equality equ curKey-> length)
            {
                curKey-> sym = keyTab[j]-> sym;
            }
        }
        j++;
    }
}

void initKeyTab()
{
    keyTab = (keyTab_t) malloc(KEYTABLENGTH * sizeof(key_type));

    int i = 0;
    while (i < KEYTABLENGTH)
    {
        keyTab[i] = (key_type) malloc(sizeof(struct key));
        i++;
    }

    keyTab[0]-> sym = AND;
    keyTab[0]-> value = "and";
    keyTab[0]-> length = 3;

    keyTab[1]-> sym = INVOL;
    keyTab[1]-> value = "involve";
    keyTab[1]-> length = 7;

    keyTab[2]-> sym = OR;
    keyTab[2]-> value = "or";
    keyTab[2]-> length = 2;

    keyTab[3]-> sym = FUNC;
    keyTab[3]-> value = "function";
    keyTab[3]-> length = 8;

    keyTab[4]-> sym = EQL;
    keyTab[4]-> value = "equ";
    keyTab[4]-> length = 3;

    keyTab[5]-> sym = NEQ;
    keyTab[5]-> value = "neq";
    keyTab[5]-> length = 3;

    keyTab[6]-> sym = IF;
    keyTab[6]-> value = "if";
    keyTab[6]-> length = 2;

    keyTab[7]-> sym = ELIF;
    keyTab[7]-> value = "elif";
    keyTab[7]-> length = 4;

    keyTab[8]-> sym = ELSE;
    keyTab[8]-> value = "else";
    keyTab[8]-> length = 4;

    keyTab[9]-> sym = WHILE;
    keyTab[9]-> value = "while";
    keyTab[9]-> length = 5;

    keyTab[10]-> sym = SEQ;
    keyTab[10]-> value = "sequence";
    keyTab[10]-> length = 8;

    keyTab[11]-> sym = STRUCT;
    keyTab[11]-> value = "struct";
    keyTab[11]-> length = 6;

    keyTab[12]-> sym = TYP;
    keyTab[12]-> value = "char";
    keyTab[12]-> length = 4;

    keyTab[13]-> sym = TYP;
    keyTab[13]-> value = "int";
    keyTab[13]-> length = 3;

    keyTab[14]-> sym = PTR;
    keyTab[14]-> value = "ptr";
    keyTab[14]-> length = 3;

    keyTab[15]-> sym = CONST;
    keyTab[15]-> value = "const";
    keyTab[15]-> length = 5;

    keyTab[16]-> sym = TYP;
    keyTab[16]-> value = "bool";
    keyTab[16]-> length = 4;

    keyTab[17]-> sym = TYP;
    keyTab[17]-> value = "void";
    keyTab[17]-> length = 4;

    keyTab[18]-> sym = BOOL;
    keyTab[18]-> value = "true";
    keyTab[18]-> length = 4;

    keyTab[19]-> sym = BOOL;
    keyTab[19]-> value = "false";
    keyTab[19]-> length = 5;

    keyTab[20]-> sym = RETURN;
    keyTab[20]-> value = "return";
    keyTab[20]-> length = 6;

    keyTab[21]-> sym = TYPEDEF;
    keyTab[21]-> value = "typedef";
    keyTab[21]-> length = 7;

    keyTab[22]-> sym = NEW;
    keyTab[22]-> value = "new";
    keyTab[22]-> length = 3;
}

void nextChar()
{
	if (read neq EOF)
	{
	    read = fscanf (file, "%c", &current);
		checkPos();
		if(curKey-> length > VALLENGTH)
        {
            printf("IdentifierName is to long at Col: %d    and Line: %d\n", colCounter, lnCounter);
            exit(1);
        }
		curKey-> value[curKey-> length] = current;
        curKey-> length = curKey-> length + 1;
	}
	else
	{
	    curKey-> sym = ENDF;
	    printf("EOF!\n");
        fclose(file);
	}
}

void checkPos()
{
    colCounter = colCounter + 1;
    if(current equ '\n')
    {
        colCounter = 0;
        lnCounter = lnCounter + 1;
    }
}

void mark(char ptr msg, int err)
{
    if(err equ 1)
    {
        errCount = errCount + 1;
        printf("%d: ERROR: %s at Line: %d   Col: %d\n", errCount, msg, curKey-> line, curKey-> column);
        fprintf(logfile,"%d: ERROR: %s at Line: %d   Col: %d\n", errCount, msg, curKey-> line, curKey-> column);
    }
    else
    {
        printf("INFO: %s at Line: %d   Col: %d\n", msg, curKey-> line, curKey-> column);
        fprintf(logfile,"INFO: %s at Line: %d   Col: %d\n", msg, curKey-> line, curKey-> column);
    }
}

void clearScanner()
{
    fclose(logfile);
}

string_t getCurValue()
{
    string_t value = (string_t) malloc(curKey-> length * sizeof(char));
    strncpy(value, curKey-> value, curKey-> length);
    value[curKey-> length] = '\0';
    mark(value, 0);
    return value;
}

